package singleflight

import (
	"sync"
)

type call struct {
	// 对相同的key，用同一个wait group做同步等待
	wg		sync.WaitGroup
	// func的返回值
	val		interface{}
	err		error
}

type Group struct {
	// 保证修改操作是串行的
	mu	sync.Mutex
	// 记录key-call
	m	map[string]*call
}

func (g *Group) Do(key string, fn func()(interface{}, error)) (interface{}, error) {
	g.mu.Lock()
	if g.m == nil {
		g.m = make(map[string]*call)
	}
	if c, ok := g.m[key]; ok {
		g.mu.Unlock()
		c.wg.Wait()
		return c.val, c.err
	}
	c := new(call)
	c.wg.Add(1)
	g.m[key] = c
	g.mu.Unlock()

	c.val, c.err = fn()
	c.wg.Done()

	g.mu.Lock()
	delete(g.m, key)
	g.mu.Unlock()

	return c.val, c.err
}